/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.pehulja.mmdo.coursework.gui.graph;

import static java.awt.Color.black;
import static java.awt.Color.lightGray;
import static java.awt.Color.red;
import static java.awt.Color.white;
import static java.awt.Color.BLUE;
import static java.awt.Color.MAGENTA;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.LayoutManager;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.swing.JPanel;

public class JPanelGraph extends JPanel {

    private static final long serialVersionUID = 1L;
    private double xFrom, xTo, xScale, yScale, factor, yFrom, yTo;
    //Map<Double, Double> points = new TreeMap<Double, Double>(); // @jve:decl-index=0:
    List<Point> area;
    List<Line> lines;

    public JPanelGraph() {
        // TODO Auto-generated constructor stub
        super();
        area = new ArrayList<Point>();
        
        xFrom = -10; 
        xTo = 10;
        yFrom = -10;
        yTo = 10;
        
        factor = 1;
        initialize();
        lines = new ArrayList<Line>();
    }

    public JPanelGraph(LayoutManager arg0) {
        super(arg0);
        // TODO Auto-generated constructor stub
        initialize();
    }

    public JPanelGraph(boolean arg0) {
        super(arg0);
        // TODO Auto-generated constructor stub
        initialize();
    }

    public JPanelGraph(LayoutManager arg0, boolean arg1) {
        super(arg0, arg1);
        // TODO Auto-generated constructor stub
        initialize();
    }

    public void addPoint(double x, double y) {
        area.add(new Point(x, y));
    }

    public void clearArea() {
        area = new ArrayList<Point>();
    }

    public double getxFrom() {
        return xFrom;
    }

    public void setxFrom(double xFrom) {
        this.xFrom = xFrom;
    }

    public double getxTo() {
        return xTo;
    }

    public void setxTo(double xTo) {
        this.xTo = xTo;
    }

    public void addLine(double x1, double y1, double x2, double y2, String label) {
        lines.add(new Line(x1, y1, x2, y2, label));
    }

    public void addLine(Line line) {
        lines.add(line);
        xFrom = line.getPointA().getX();
        yFrom = line.getPointA().getY();
        xTo = line.getPointB().getX();
        yTo = line.getPointB().getY();
    }

    /**
     * @param args
     */
    private boolean isReadyToPaint() {
        return lines != null && lines.size() > 0;
    }

    private void initialize() {
        this.setSize(300, 200);
        this.setLayout(new FlowLayout());
    }

    public void left() {
        if (isReadyToPaint()) {
            xFrom -= factor;
            xTo -= factor;
        }
    }

    public void right() {
        if (isReadyToPaint()) {
            xFrom += factor;
            xTo += factor;
        }
    }

    public void up() {
        if (isReadyToPaint()) {
            yFrom += factor * 5;
            yTo += factor * 5;
        }
    }

    public void down() {
        if (isReadyToPaint()) {
            yFrom -= factor * 5;
            yTo -= factor * 5;
        }
    }

    public void verticalMove(double x) {
        if (isReadyToPaint()) {
            x /= ((yScale) * factor);
            yFrom -= x;
            yTo -= x;
        }

    }

    public void horisontalMove(double x) {
        if (isReadyToPaint()) {
            x /= ((xScale) * factor);
            xFrom += x;
            xTo += x;
        }
    }

    public void MinusScale() {
        if (isReadyToPaint()) {
            factor *= 2;

            if (yFrom > yTo) {
                double temp = yFrom;
                yFrom = yTo;
                yTo = temp;
            }
        }
    }

    public void PlusScale() {
        if (isReadyToPaint()) {
            factor /= 2;

            if (yFrom > yTo) {
                double temp = yFrom;
                yFrom = yTo;
                yTo = temp;
            }
        }
    }

    public void ChangeScale(double mnoz) {
        if (isReadyToPaint()) {
            factor *= mnoz;
            if (yFrom > yTo) {
                double temp = yFrom;
                yFrom = yTo;
                yTo = temp;
            }
        }
    }

    private void paintFunc(Graphics g, Line line, int x0, int y0, double xScale, double yScale) {
        if (line != null) {
            int x1 = x0 + (int) (line.getPointA().getX() * xScale);
            int y1 = y0 - (int) (line.getPointA().getY() * yScale);
            int x2 = x0 + (int) (line.getPointB().getX() * xScale);
            int y2 = y0 - (int) (line.getPointB().getY() * yScale);

            g.setColor(BLUE);

            /*g.fillOval((int)(x1-deltaX), (int)(y1-deltaY), widthPoint, heightPoint);
             g.fillOval((int)(x2-deltaX), (int)(y2-deltaY), widthPoint, heightPoint);*/

            g.setColor(MAGENTA);
            g.setFont(Font.getFont("Times New Roman"));
            g.drawString(line.getLabel(), x1, y1);


            if (x1 > x2) {
                x1 += Short.MAX_VALUE;
                x2 -= Short.MAX_VALUE;
            } else {
                x1 -= Short.MAX_VALUE;
                x2 += Short.MAX_VALUE;
            }
            if (y1 > y2) {
                y1 += Short.MAX_VALUE;
                y2 -= Short.MAX_VALUE;
            } else {
                y1 -= Short.MAX_VALUE;
                y2 += Short.MAX_VALUE;
            }


            g.setColor(red);
            g.drawLine(x1, y1, x2, y2);


        }
    }

    public void paintArea(Graphics g, int x0, int y0, double xScale, double yScale) {
        if (area != null && area.size() >= 3) {
            int[] xPoints = new int[area.size()];
            int[] yPoints = new int[area.size()];
            for (int i = 0; i < area.size(); i++) {
                xPoints[i] = (x0 + (int) (area.get(i).getX() * xScale));
                yPoints[i] = (y0 - (int) (area.get(i).getY() * yScale));
            }
            g.setColor(MAGENTA);
            g.fillPolygon(xPoints, yPoints, area.size());
           
        }
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        
            System.out.println("paint");
            double xMin, xMax, yMin, yMax;
            int width = getWidth();
            int height = getHeight();
            xMin = xFrom == xTo ? -5 : xFrom * factor;
            xMax = xFrom == xTo ? 5 : xTo * factor;

            yMin = yFrom * factor;
            yMax = yTo * factor;


            xScale = width / (xMax - xMin);
            yScale = height / (yMax - yMin);

            int x0 = (int) (-xMin * xScale);
            int y0 = (int) (yMax * yScale);
            g.setColor(white);
            g.fillRect(0, 0, width, height);
            double xStep = (xMax - xMin) / 10; // Крок сітки
            for (double dx = xStep; dx < xMax; dx += xStep) {
                int x = x0 + (int) (dx * xScale);
                g.setColor(lightGray);
                g.drawLine(x, 0, x, height);
                g.setColor(black);
                g.drawString(roundResult(dx, 2) + "", x + 2, 10);
            }
            for (double dx = -xStep; dx >= xMin; dx -= xStep) {
                int x = x0 + (int) (dx * xScale);
                g.setColor(lightGray);
                g.drawLine(x, 0, x, height);
                g.setColor(black);
                g.drawString(roundResult(dx, 2) + "", x + 2, 10);
            }

            double yStep = (yMax - yMin) / 10; // Крок сітки
            while (yStep * yScale < 20) {
                yStep *= 10;
            }
            for (double dy = yStep; dy < yMax; dy += yStep > 0 ? yStep : -1 * yStep) {
                int y = y0 - (int) (dy * yScale);
                g.setColor(lightGray);
                g.drawLine(0, y, width, y);
                g.setColor(black);
                g.drawString(roundResult(dy, 2) + "", 2, y - 2);
            }

            for (double dy = -yStep; dy > yMin; dy -= yStep > 0 ? yStep : -1 * yStep) {
                int y = y0 - (int) (dy * yScale);
                g.setColor(lightGray);
                g.drawLine(0, y, width, y);
                g.setColor(black);
                g.drawString(roundResult(dy, 2) + "", 2, y - 2);
            }

            // Вісі:
            g.setColor(black);
            g.drawLine(x0, 0, x0, height);
            g.drawLine(0, y0, width, y0);
            g.drawString("0.0", 2, y0 - 2);
            g.drawString("X", width - 10, y0 - 2);
            g.drawString("Y", x0 + 2, 10);

            if(lines!=null)
                for (Line line : lines)
                    paintFunc(g, line, x0, y0, xScale, yScale);
            paintArea(g, x0, y0, xScale, yScale);


    }

    double roundResult(double d, int precise) {
        precise = 10 ^ precise;
        d = d * precise;
        int i = (int) Math.round(d);
        return (double) i / precise;
    }
}
